package com.intmall.security.config;

import com.intmall.security.handler.MyAccessDeniedHandler;
import com.intmall.security.service.UserDetailsServiceImpl;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.web.SecurityFilterChain;
import org.springframework.security.web.authentication.rememberme.JdbcTokenRepositoryImpl;
import org.springframework.security.web.authentication.rememberme.PersistentTokenRepository;

import javax.sql.DataSource;

@Configuration
public class SecurityConfig {

    @Autowired
    private MyAccessDeniedHandler myAccessDeniedHandler;

    @Autowired
    private UserDetailsServiceImpl userDetailsService;

    @Autowired
    private DataSource dataSource;

    @Bean
    SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
        // 表单提交自定义登录页
        http.formLogin()
                .usernameParameter("uname")
                .passwordParameter("pwd")
                // 登录提交处理请求的地址
                .loginProcessingUrl("/login")
                .loginPage("/login.html")
                // 登录成功后跳转页面，必须是Post请求
                .defaultSuccessUrl("/toMain")
                //自定义成功处理器，与defaultSuccessUrl不能同时使用
//                .successHandler(new MyAuthenticationSuccessHandler("main.html"))
                // 登录失败后跳转页面，必须是Post请求
                .failureForwardUrl("/toFail")

//                .failureHandler(new MyAuthenticationFailureHandler("/fail.html"))
        ;

        // 认证授权
        http.authorizeRequests()
                // login.html不需要被认证
                .antMatchers("/login.html").permitAll()
//                .antMatchers("/fail.html").permitAll()
                .antMatchers("/fail.html").access("permitAll")
                .antMatchers("/js/**", "/css/**", "/images/**").permitAll()
                // 按后缀指定放行文件
//                .antMatchers("/**/*.png").permitAll()
//                .regexMatchers(".+[.]png").permitAll()
//                .regexMatchers(HttpMethod.POST, "/demo").permitAll()
                // 如果指定了servletContext路径(项目名称)，需要加上servletPath
//                .mvcMatchers("/demo").servletPath("/xxxx").permitAll()
//                .antMatchers("/xxxx/demo").permitAll()
                // 权限区分大小写
//                .antMatchers("/main1.html").hasAuthority("admin")
//                .antMatchers("/main1.html").hasAnyAuthority("admin", "adminN")
                // 角色校验会自动添加ROLE_,这里不能再加前缀；区分大小写
//                .antMatchers("/main1.html").hasRole("normal")
//                .antMatchers("/main1.html").hasAnyRole("normal", "Normal")
//                .antMatchers("/main1.html").hasIpAddress("127.0.0.1")
                // 所有请求都必须被认证(登录后访问)
                .anyRequest().authenticated()
//                .anyRequest().access("@myServiceImpl.hasPermission(request, authentication)")
        ;

        http.csrf().disable();

        http.rememberMe()
                // token失效时间，秒
                .tokenValiditySeconds(600)
                // form表单字段名称
//                .rememberMeParameter("rememberMe")
                .tokenRepository(getPersistentTokenRepository())
                .userDetailsService(userDetailsService);

        // 异常处理
        http.exceptionHandling()
                .accessDeniedHandler(myAccessDeniedHandler);

        http.logout()
                // 退出登录跳转页面
                .logoutSuccessUrl("/login.html");
        return http.build();
    }

//    @Bean
//    WebSecurityCustomizer webSecurityCustomizer() {
//        return new WebSecurityCustomizer() {
//            @Override
//            public void customize(WebSecurity web) {
//                web.ignoring().antMatchers("/hello");
//            }
//        };
//    }

    @Bean
    public PasswordEncoder getPasswordEncoder() {
        return new BCryptPasswordEncoder();
    }

    @Bean
    public PersistentTokenRepository getPersistentTokenRepository() {
        JdbcTokenRepositoryImpl jdbcTokenRepository = new JdbcTokenRepositoryImpl();
        jdbcTokenRepository.setDataSource(dataSource);
        // 自动建表，第一次启动时候需要，第二次启动需要注释掉
//        jdbcTokenRepository.setCreateTableOnStartup(true);
        return jdbcTokenRepository;
    }
}
